From d3c350b97d333bdfd17ae8cc53a11ca036d00913 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Jul 2014 08:45:42 -0700 Subject: [PATCH] Refactor fingerprint logic out of cargo_rustc --- src/cargo/ops/cargo_rustc/fingerprint.rs | 62 ++++++++++++++++++++++++ src/cargo/ops/cargo_rustc/mod.rs | 53 ++------------------ 2 files changed, 67 insertions(+), 48 deletions(-) create mode 100644 src/cargo/ops/cargo_rustc/fingerprint.rs diff --git a/src/cargo/ops/cargo_rustc/fingerprint.rs b/src/cargo/ops/cargo_rustc/fingerprint.rs new file mode 100644 index 000000000..7bee9f9b8 --- /dev/null +++ b/src/cargo/ops/cargo_rustc/fingerprint.rs @@ -0,0 +1,62 @@ +use std::hash::Hasher; +use std::hash::sip::SipHasher; +use std::io::File; + +use core::{Package, Target}; +use util; +use util::{CargoResult, Fresh, Dirty, Freshness}; + +use super::job::Job; +use super::context::Context; + +/// Calculates the fingerprint of a package's targets and prepares to write a +/// new fingerprint. +/// +/// This function will first calculate the freshness of the package and return +/// it as the first part of the return tuple. It will then prepare a job to +/// update the fingerprint if this package is actually rebuilt as part of +/// compilation, returning the job as the second part of the tuple. +pub fn prepare(cx: &mut Context, pkg: &Package, + targets: &[&Target]) -> CargoResult<(Freshness, Job)> { + let fingerprint_loc = cx.dest().join(format!(".{}.fingerprint", + pkg.get_name())); + + let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, + cx, targets)); + let write_fingerprint = Job::new(proc() { + try!(File::create(&fingerprint_loc).write_str(fingerprint.as_slice())); + Ok(Vec::new()) + }); + Ok((if is_fresh {Fresh} else {Dirty}, write_fingerprint)) +} + +fn is_fresh(dep: &Package, loc: &Path, cx: &mut Context, targets: &[&Target]) + -> CargoResult<(bool, String)> { + let new_pkg_fingerprint = format!("{}{}", cx.rustc_version, + try!(dep.get_fingerprint(cx.config))); + + let new_fingerprint = fingerprint(new_pkg_fingerprint, hash_targets(targets)); + + let mut file = match File::open(loc) { + Ok(file) => file, + Err(..) => return Ok((false, new_fingerprint)), + }; + + let old_fingerprint = try!(file.read_to_string()); + + log!(5, "old fingerprint: {}", old_fingerprint); + log!(5, "new fingerprint: {}", new_fingerprint); + + Ok((old_fingerprint == new_fingerprint, new_fingerprint)) +} + +fn hash_targets(targets: &[&Target]) -> u64 { + let hasher = SipHasher::new_with_keys(0,0); + let targets = targets.iter().map(|t| (*t).clone()).collect::>(); + hasher.hash(&targets) +} + +fn fingerprint(package: String, profiles: u64) -> String { + let hasher = SipHasher::new_with_keys(0,0); + util::to_hex(hasher.hash(&(package, profiles))) +} diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 619e4e127..9d28b09ed 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -1,8 +1,4 @@ use std::collections::HashMap; -use std::hash::Hasher; -use std::hash::sip::SipHasher; -use std::io::File; -use std::os::args; use term::color::YELLOW; use core::{Package, PackageSet, Target, Resolve}; @@ -15,6 +11,7 @@ use self::context::Context; mod job; mod context; +mod fingerprint; type Args = Vec; @@ -106,8 +103,7 @@ fn compile<'a>(targets: &[&Target], pkg: &'a Package, cx: &mut Context, // Note that bins can all be built in parallel because they all depend on // one another, but libs must be built sequentially because they may have // interdependencies. - let mut libs = Vec::new(); - let mut bins = Vec::new(); + let (mut libs, mut bins) = (Vec::new(), Vec::new()); for &target in targets.iter() { let job = rustc(pkg, target, cx); if target.is_lib() { @@ -124,15 +120,8 @@ fn compile<'a>(targets: &[&Target], pkg: &'a Package, cx: &mut Context, // TODO: Can a fingerprint be per-target instead of per-package? Doing so // would likely involve altering the granularity of key for the // dependency queue that is later used to run jobs. - let fingerprint_loc = cx.dest().join(format!(".{}.fingerprint", - pkg.get_name())); - - let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, cx, - targets)); - let write_fingerprint = Job::new(proc() { - try!(File::create(&fingerprint_loc).write_str(fingerprint.as_slice())); - Ok(Vec::new()) - }); + let (freshness, write_fingerprint) = + try!(fingerprint::prepare(cx, pkg, targets)); // Note that we build the job backwards because each job will produce more // work. @@ -140,42 +129,10 @@ fn compile<'a>(targets: &[&Target], pkg: &'a Package, cx: &mut Context, let build_libs = Job::all(libs, bins); let job = Job::all(build_cmds, vec![build_libs]); - jobs.push((pkg, if is_fresh {Fresh} else {Dirty}, job)); + jobs.push((pkg, freshness, job)); Ok(()) } -fn is_fresh(dep: &Package, loc: &Path, - cx: &mut Context, targets: &[&Target]) -> CargoResult<(bool, String)> -{ - let new_pkg_fingerprint = format!("{}{}", cx.rustc_version, - try!(dep.get_fingerprint(cx.config))); - - let new_fingerprint = fingerprint(new_pkg_fingerprint, hash_targets(targets)); - - let mut file = match File::open(loc) { - Ok(file) => file, - Err(..) => return Ok((false, new_fingerprint)), - }; - - let old_fingerprint = try!(file.read_to_string()); - - log!(5, "old fingerprint: {}", old_fingerprint); - log!(5, "new fingerprint: {}", new_fingerprint); - - Ok((old_fingerprint == new_fingerprint, new_fingerprint)) -} - -fn hash_targets(targets: &[&Target]) -> u64 { - let hasher = SipHasher::new_with_keys(0,0); - let targets = targets.iter().map(|t| (*t).clone()).collect::>(); - hasher.hash(&targets) -} - -fn fingerprint(package: String, profiles: u64) -> String { - let hasher = SipHasher::new_with_keys(0,0); - util::to_hex(hasher.hash(&(package, profiles))) -} - fn compile_custom(pkg: &Package, cmd: &str, cx: &Context) -> Job { // FIXME: this needs to be smarter about splitting -- 2.30.2